package com.rulestech.framework.unittest;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;

public abstract class SpreadsheetTestCaseBuilder implements TestCaseBuilder {

	@Override
	public Collection<DataDrivenTestCase> getTestCases() {
		return data;
	}
	
    private transient Collection<DataDrivenTestCase> data = new ArrayList<DataDrivenTestCase>();
    private transient Row header = null;

    public SpreadsheetTestCaseBuilder(String fileName)  throws IOException {
		this(SpreadsheetTestCaseBuilder.class.getResourceAsStream (fileName));
    }
    
    public SpreadsheetTestCaseBuilder(final InputStream excelInputStream) throws IOException {
        this.data = loadFromSpreadsheet(excelInputStream);
    }


    private Collection<DataDrivenTestCase> loadFromSpreadsheet(final InputStream excelFile)
            throws IOException {
        HSSFWorkbook workbook = new HSSFWorkbook(excelFile);

        Sheet sheet = workbook.getSheetAt(0);
        header = sheet.getRow(0);

        return convertDatasheetToTestCases(sheet);
    }
    
    protected boolean isEmpty(final Row row) {
        Cell firstCell = row.getCell(0);
        boolean rowIsEmpty = (firstCell == null)
                || (firstCell.getCellType() == Cell.CELL_TYPE_BLANK);
        return rowIsEmpty;
    }
    
    public Row getHeader(){
    	return header;
    }
    
    protected boolean isHeader(Row row){
    	return row.getRowNum() == 0;
    }
    
    private Cell getCell(Row row, String columnName){
    	for (int i =0; i< header.getPhysicalNumberOfCells(); i++){
    		if (columnName.equals(header.getCell(i).getRichStringCellValue().getString())){
    			return row.getCell(i);
    		}
    	}
    	//could not file
    	throw new RuntimeException("You are retriving the value for " + columnName + " on row " + row.getRowNum() + " but there is no value in it!");
    }
    
    protected int getCellValueAsInt(Row row, String columnName){
    	return (new Double(getCell(row, columnName).getNumericCellValue())).intValue();
    }
    
    protected boolean getCellValueAsBoolean(Row row, String columnName){
    	String value = getCellValueAsString(row, columnName);
    	if ("Y".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value) || "yes".equalsIgnoreCase(value)){
    		return true;
    	}
    	if ("N".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value) || "no".equalsIgnoreCase(value)){
    		return false;
    	}
    	return true; //by default or other invalid values.
    }
    
    protected String getCellValueAsString (Row row, String columnName){
    	Cell cell = getCell(row, columnName);
    	if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC){
    		return Double.toString(cell.getNumericCellValue());
    	}
    	else{
    		return cell.getStringCellValue();
    	}
    }
    
    protected double getCellValueAsDouble(Row row, String columnName){
    	return getCell(row, columnName).getNumericCellValue();
    }
    
	private Collection<DataDrivenTestCase> convertDatasheetToTestCases(Sheet sheet) {  
		Collection<DataDrivenTestCase> result = new ArrayList<DataDrivenTestCase>();
		for (Row row : sheet) {
			if (isEmpty(row)) {
				break;
			} else {
				if (isHeader(row)){
					continue;
				}
				else{
					result.add(convertOneRowPerTestCase(row));
				}
			}
		}
		return result;
	}

	/**
	 * Convert one row to one DataDrivenTestCase
	 * 
	 * @param row representing one row in the spreadsheet
	 * @return one DataDrivenTestCase
	 */
	protected abstract DataDrivenTestCase convertOneRowPerTestCase(Row row);
}
